package com.ht.aems.fesmodel.persist;

import com.ht.aems.dbservice.ConnectionFactory;
import com.ht.aems.dbservice.SqlExecutor;
import com.ht.aems.fesmodel.FesPersistence;
import com.ht.aems.fesmodel.HisDataProvider;
import com.ht.aems.fesmodel.data.AnalogPoint;
import com.ht.aems.fesmodel.data.DiscretePoint;
import com.ht.aems.fesmodel.data.MeasurePoint;
import org.apache.log4j.Logger;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author YanXue
 *         Date: 2010-8-6 Time: 16:03:31
 */

public class HisDataSqlPersist implements HisDataProvider {
    private static Logger log = Logger.getLogger(HisDataSqlPersist.class);
    String database;
    SimpleDateFormat minuteFormat = new SimpleDateFormat("yyyyMMdd");
    SimpleDateFormat dayFormat = new SimpleDateFormat("yyyyMM");
    SimpleDateFormat monthFormat = new SimpleDateFormat("yyyy");

    public Map<Integer, Double> getYearAnalog(int[] nids, Date date) {
        Connection conn = database != null ? ConnectionFactory.createConnection(database) : ConnectionFactory.createConnection();
        Map<Integer, Double> result = new HashMap<Integer, Double>(nids.length);
        try {
            Calendar c = Calendar.getInstance();
            c.setTime(date);
            int year = c.get(Calendar.YEAR);
            ResultSet r = SqlExecutor.executeQuery(conn, "select * from " + FesPersistence.TABLE_ALG_YEAR + " where nYear=" + year);//todo: wrong
            while (r.next()) {
                Double d = r.getDouble("fValue");
                result.put(r.getInt("nId"), d);
            }
            r.close();
        } catch (Exception e) {
            e.printStackTrace();
            log.warn(e);
        } finally {
            try {
                if (conn != null)
                    conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    public Double get(AnalogPoint p, long time) {
        int nid = MeasurePoint.getNID(p.getRtuId(), p.getPointNum());
        Map<Integer, Double> result = null;
        int type = p.getMeasureType();
        switch (type) {
            case MeasurePoint.MINUTE:
                result = getMinuteAnalog(new int[]{nid}, new Date(time));
                break;
            case MeasurePoint.DAY:
                result = getDayAnalog(new int[]{nid}, new Date(time));
                break;
            case MeasurePoint.MONTH:
                result = getMonthAnalog(new int[]{nid}, new Date(time));
                break;
            case MeasurePoint.YEAR:
                result = getYearAnalog(new int[]{nid}, new Date(time));
                break;
        }
        if (result != null && result.containsKey(nid))
            return result.get(nid);
        return null;
    }

    public Integer get(DiscretePoint p, long time) {
        int nid = MeasurePoint.getNID(p.getRtuId(), p.getPointNum());
        Map<Integer, Integer> result = null;
        int type = p.getMeasureType();
        switch (type) {
            case MeasurePoint.MINUTE:
                result = getMinuteDiscrete(new int[]{nid}, new Date(time));
                break;
            case MeasurePoint.DAY:
                result = getDayDiscrete(new int[]{nid}, new Date(time));
                break;
            case MeasurePoint.MONTH:
                result = getMonthDiscrete(new int[]{nid}, new Date(time));
                break;
            case MeasurePoint.YEAR:
                result = getYearDiscrete(new int[]{nid}, new Date(time));
                break;
        }
        if (result != null && result.containsKey(nid))
            return result.get(nid);
        return null;
    }

    private Map<Integer, Integer> getYearDiscrete(int[] nids, Date date) {
        Connection conn = database != null ? ConnectionFactory.createConnection(database) : ConnectionFactory.createConnection();
        Map<Integer, Integer> result = new HashMap<Integer, Integer>(nids.length);
        try {
            Calendar c = Calendar.getInstance();
            c.setTime(date);
            int year = c.get(Calendar.YEAR);
            ResultSet r = SqlExecutor.executeQuery(conn, "select * from " + FesPersistence.TABLE_DIS_YEAR + " where nYear=" + year);//todo: wrong
            while (r.next()) {
                int d = r.getInt("nValue");
                result.put(r.getInt("nId"), d);
            }
            r.close();
        } catch (Exception e) {
            e.printStackTrace();
            log.warn(e);
        } finally {
            try {
                if (conn != null)
                    conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    private Map<Integer, Integer> getMonthDiscrete(int[] nids, Date month) {
        Connection conn = database != null ? ConnectionFactory.createConnection(database) : ConnectionFactory.createConnection();
        Map<Integer, Integer> result = new HashMap<Integer, Integer>(nids.length);
        try {
            Calendar c = Calendar.getInstance();
            c.setTime(month);
            int monthOfYear = c.get(Calendar.MONTH);
            ResultSet r = SqlExecutor.executeQuery(conn, "select * from " + FesPersistence.TABLE_DIS + "_" + monthFormat.format(month) + " where nMonth=" + monthOfYear);//todo: wrong
            while (r != null && r.next()) {
                int d = r.getInt("nValue");
                result.put(r.getInt("nId"), d);
            }
            r.close();
        } catch (Exception e) {
            e.printStackTrace();
            log.warn(e);
        } finally {
            try {
                if (conn != null)
                    conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    private Map<Integer, Integer> getDayDiscrete(int[] nids, Date month) {
        Connection conn = database != null ? ConnectionFactory.createConnection(database) : ConnectionFactory.createConnection();
        Map<Integer, Integer> result = new HashMap<Integer, Integer>(nids.length);
        try {
            Calendar c = Calendar.getInstance();
            c.setTime(month);
            int dayOfMonth = c.get(Calendar.DAY_OF_MONTH);
            ResultSet r = SqlExecutor.executeQuery(conn, "select * from " + FesPersistence.TABLE_DIS + "_" + dayFormat.format(month) + " where nDay=" + dayOfMonth);//todo: wrong
            while (r.next()) {
                int d = r.getInt("nValue");
                result.put(r.getInt("nId"), d);
            }
            r.close();
        } catch (Exception e) {
            e.printStackTrace();
            log.warn(e);
        } finally {
            try {
                if (conn != null)
                    conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    private Map<Integer, Integer> getMinuteDiscrete(int[] nids, Date minute) {
        Connection conn = database != null ? ConnectionFactory.createConnection(database) : ConnectionFactory.createConnection();
        Map<Integer, Integer> result = new HashMap<Integer, Integer>(nids.length);
        try {
            Calendar c = Calendar.getInstance();
            c.setTime(minute);
            int hour = c.get(Calendar.HOUR_OF_DAY);
            int minuteCount = 60 * hour + c.get(Calendar.MINUTE);
            for (int nid : nids) {
                ResultSet r = SqlExecutor.executeQuery(conn, "select * from " + FesPersistence.TABLE_DIS + "_" + minuteFormat.format(minute) + " where nminute=" + minuteCount + "and nid=" + nid);
                while (r.next()) {
                    int d = r.getInt("nValue");
                    result.put(nid, d);
                }
                r.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.warn(e);
        } finally {
            try {
                if (conn != null)
                    conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    public Map<Integer, Double> getMonthAnalog(int[] nids, Date month) {
        Connection conn = database != null ? ConnectionFactory.createConnection(database) : ConnectionFactory.createConnection();
        Map<Integer, Double> result = new HashMap<Integer, Double>(nids.length);
        try {
            Calendar c = Calendar.getInstance();
            c.setTime(month);
            int monthOfYear = c.get(Calendar.MONTH);
            ResultSet r = SqlExecutor.executeQuery(conn, "select * from " + FesPersistence.TABLE_ALG + "_" + monthFormat.format(month) + " where nMonth=" + monthOfYear);//todo: wrong
            while (r != null && r.next()) {
                Double d = r.getDouble("fValue");
                result.put(r.getInt("nId"), d);
            }
            r.close();
        } catch (Exception e) {
            e.printStackTrace();
            log.warn(e);
        } finally {
            try {
                if (conn != null)
                    conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    public Map<Long, Double> getMinuteAnalogInSameDay(int nid, long start, long end) {
        if ((end - start) > (24l * 3600l * 1000l))
            return null;
        Map<Long, Double> result = new HashMap<Long, Double>();
        Date day = new Date(start);
        String dayString = minuteFormat.format(day);
        String tableName = FesPersistence.TABLE_ALG + "_" + dayString;
        Calendar c = Calendar.getInstance();
        c.setTimeInMillis(start);
        int hour = c.get(Calendar.HOUR_OF_DAY);
        int startMinute = hour * 60 + c.get(Calendar.MINUTE);
        c.setTimeInMillis(end);
        hour = c.get(Calendar.HOUR_OF_DAY);
        int endMinute = hour * 60 + c.get(Calendar.MINUTE);
        Connection conn = database != null ? ConnectionFactory.createConnection(database) : ConnectionFactory.createConnection();
        String sql = "select * from " + tableName + " where nminute >=" + startMinute + " and nminute <=" + endMinute + " and nid=" + nid;
        c.set(Calendar.HOUR_OF_DAY, 0);
        c.set(Calendar.MINUTE, 0);
        c.set(Calendar.SECOND, 0);
        c.set(Calendar.MILLISECOND, 0);
        try {
            ResultSet r = SqlExecutor.executeQuery(conn, sql);
            while (r.next()) {
                int minute = r.getInt("nminute");
                result.put(minute * 60000l + c.getTimeInMillis(), (double) r.getFloat("fvalue"));
            }
            r.close();
        } catch (Exception e) {
            e.printStackTrace();
            log.warn(e);
        } finally {
            try {
                if (conn != null)
                    conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    public Map<Integer, Double> getMinuteAnalog(int[] nids, Date minute) {
        Connection conn = database != null ? ConnectionFactory.createConnection(database) : ConnectionFactory.createConnection();
        Map<Integer, Double> result = new HashMap<Integer, Double>(nids.length);
        try {
            Calendar c = Calendar.getInstance();
            c.setTime(minute);
            int hour = c.get(Calendar.HOUR_OF_DAY);
            int minuteCount = 60 * hour + c.get(Calendar.MINUTE);
            for (int nid : nids) {
                ResultSet r = SqlExecutor.executeQuery(conn, "select * from " + FesPersistence.TABLE_ALG + "_" + minuteFormat.format(minute) + " where nminute=" + minuteCount + "and nid=" + nid);
                while (r.next()) {
                    Double d = (double) r.getFloat("fValue");
                    result.put(nid, d);
                }
                r.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.warn(e);
        } finally {
            try {
                if (conn != null)
                    conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    public Map<Integer, Double> getDayAnalog(int[] nids, Date month) {
        Connection conn = database != null ? ConnectionFactory.createConnection(database) : ConnectionFactory.createConnection();
        Map<Integer, Double> result = new HashMap<Integer, Double>(nids.length);
        try {
            Calendar c = Calendar.getInstance();
            c.setTime(month);
            int dayOfMonth = c.get(Calendar.DAY_OF_MONTH);
            ResultSet r = SqlExecutor.executeQuery(conn, "select * from " + FesPersistence.TABLE_ALG + "_" + dayFormat.format(month) + " where nDay=" + dayOfMonth);//todo: wrong
            while (r.next()) {
                Double d = r.getDouble("fValue");
                result.put(r.getInt("nId"), d);
            }
            r.close();
        } catch (Exception e) {
            e.printStackTrace();
            log.warn(e);
        } finally {
            try {
                if (conn != null)
                    conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    public Map<Long, Double> get(AnalogPoint p, long start, long end, int hisSampleType) {
        Map<Long, Double> data = new HashMap<Long, Double>();
        Connection conn = database != null ? ConnectionFactory.createConnection(database) : ConnectionFactory.createConnection();
        ResultSet r = null;
        int count = (int) ((end - start) / (24l * 3600l * 1000l)) + 1;
        try {
            if (hisSampleType == AnalogPoint.MINUTE) {
                for (int i = 0; i < count; i++) {
                    String s = minuteFormat.format(start + i * 24l * 3600l * 1000l);
                    r = SqlExecutor.executeQuery(conn, "select * from " + FesPersistence.TABLE_ALG + "_" + s + " where nid = " + p.getId());
                    while (r.next()) {
                        int minute = r.getInt("nMinute");
                        Date d = minuteFormat.parse(s);
                        long time = minute * 60000l;
                        data.put(time + d.getTime(), r.getDouble("fValue"));
                    }
                }
            } else if (hisSampleType == AnalogPoint.DAY) {
                for (int i = 0; i < count; i++) {
                    String s = dayFormat.format(start + i * 24l * 3600l * 1000l);
                    r = SqlExecutor.executeQuery(conn, "select * from " + FesPersistence.TABLE_ALG + "_" + s + " where nid = " + p.getId());
                    System.out.println();
                    while (r.next()) {
                        int day = r.getInt("nDay");
                        Date d = minuteFormat.parse(s + (day < 10 ? "0" : "") + String.valueOf(day));
                        data.put(d.getTime(), r.getDouble("fvalue"));
                    }
                }
            } else if (hisSampleType == AnalogPoint.MONTH) {
                for (int i = 0; i < count; i++) {
                    String s = monthFormat.format(start + i * 24l * 3600l * 1000l);
                    r = SqlExecutor.executeQuery(conn, "select * from " + FesPersistence.TABLE_ALG + "_" + s + " where nid = " + p.getId());
                    while (r.next()) {
                        String month = String.valueOf(r.getInt("nMonth"));
                        Date time = dayFormat.parse(s + month);
                        data.put(time.getTime(), r.getDouble("fvalue"));
                    }
                }
            } else if (hisSampleType == AnalogPoint.YEAR) {
                for (int i = 0; i < count; i++) {
                    r = SqlExecutor.executeQuery(conn, "select * from " + FesPersistence.TABLE_ALG_YEAR + " where nid = " + p.getId());
                    while (r.next()) {
                        String year = String.valueOf(r.getInt("nYear"));
                        Date d = monthFormat.parse(year);
                        data.put(d.getTime(), r.getDouble("fValue"));
                    }
                }
            }
            r.close();
        } catch (Exception e) {
            e.printStackTrace();
            log.warn(e);
        } finally {
            try {
                if (conn != null)
                    conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return data;
    }

    public Map<Long, Integer> get(DiscretePoint p, long start, long end, int hisSampleType) {
        Map<Long, Integer> data = new HashMap<Long, Integer>();
        Connection conn = database != null ? ConnectionFactory.createConnection(database) : ConnectionFactory.createConnection();
        ResultSet r = null;
        int count = (int) ((end - start) / (24l * 3600l * 1000l)) + 1;
        try {
            if (hisSampleType == DiscretePoint.MINUTE) {
                for (int i = 0; i < count; i++) {
                    String s = minuteFormat.format(start + i * 24l * 3600l * 1000l);
                    r = SqlExecutor.executeQuery(conn, "select * from " + FesPersistence.TABLE_DIS + "_" + s + " where nid = " + p.getId());
                    while (r.next()) {
                        int minute = r.getInt("nMinute");
                        long time = minute * 60000l;
                        Date d = minuteFormat.parse(s);
                        data.put(time + d.getTime(), r.getInt("nValue"));
                    }
                }
            } else if (hisSampleType == DiscretePoint.DAY) {
                for (int i = 0; i < count; i++) {
                    String s = dayFormat.format(start + i * 24l * 3600l * 1000l);
                    r = SqlExecutor.executeQuery(conn, "select * from " + FesPersistence.TABLE_DIS + "_" + s + " where nid = " + p.getId());
                    System.out.println();
                    while (r.next()) {
                        int day = r.getInt("nDay");
                        Date d = minuteFormat.parse(s + (day < 10 ? "0" : "") + String.valueOf(day));
                        data.put(d.getTime(), r.getInt("nValue"));
                    }
                }
            } else if (hisSampleType == DiscretePoint.MONTH) {
                for (int i = 0; i < count; i++) {
                    String s = monthFormat.format(start + i * 24l * 3600l * 1000l);
                    r = SqlExecutor.executeQuery(conn, "select * from " + FesPersistence.TABLE_DIS + "_" + s + " where nid = " + p.getId());
                    while (r.next()) {
                        String month = String.valueOf(r.getInt("nMonth"));
                        Date time = dayFormat.parse(s + month);
                        data.put(time.getTime(), r.getInt("nValue"));
                    }
                }
            } else if (hisSampleType == DiscretePoint.YEAR) {
                for (int i = 0; i < count; i++) {
                    r = SqlExecutor.executeQuery(conn, "select * from " + FesPersistence.TABLE_DIS_YEAR + " where nid = " + p.getId());
                    while (r.next()) {
                        String year = String.valueOf(r.getInt("nYear"));
                        Date d = monthFormat.parse(year);
                        data.put(d.getTime(), r.getInt("nValue"));
                    }
                }
            }
            r.close();
        } catch (Exception e) {
            e.printStackTrace();
            log.warn(e);
        } finally {
            try {
                if (conn != null)
                    conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return data;
    }
}
